reflect.t

documentation
 #charset "us-ascii"
 
 /* 
  *   Copyright (c) 2000, 2006 Michael J. Roberts
  *   
  *   This file is part of TADS 3.  
  */
 
 #include "tads.h"
 #include "reflect.h"
 
 /* ------------------------------------------------------------------------ */
 /*
  *   Main reflection services object.
  *   
  *   During pre-initialization, we'll plug this into the _main module's
  *   globals so that the _main module will know it can use reflection
  *   services.  
  */
 reflectionServices: PreinitObject
     /* execute preinitialization */
     execute()
     {
         /* plug ourselves into the main globals */
         mainGlobal.reflectionObj = self;
 
         /* store the main symbol table */
         symtab_ = t3GetGlobalSymbols();
 
         /* create a reverse lookup table from the main symbol table */
         if (symtab_ != nil)
         {
             /* 
              *   create a lookup table for the reverse table - it'll be
              *   the same size as the original table, so create it using
              *   the same statistics 
              */
             reverseSymtab_ = new LookupTable(symtab_.getBucketCount(),
                                              symtab_.getEntryCount());
 
             /* 
              *   for each entry in the main table, create an entry in the
              *   reverse table with the role of key and value reversed -
              *   this will allow us to look up any value and find its
              *   global symbol, if it has one 
              */
             symtab_.forEachAssoc({key, val: reverseSymtab_[val] = key});
         }
     }
 
     /*
      *   Convert a value to a symbol, or to a string representation if
      *   it's not of a symbolic type.  
      */
     valToSymbol(val)
     {
         local sym;
         
         /* the representation depends on the type */
         switch(dataType(val))
         {
         case TypeNil:
             return 'nil';
 
         case TypeTrue:
             return 'true';
 
         case TypeInt:
             return toString(val);
 
         case TypeSString:
         case TypeList:
         case TypeObject:
             /* 
              *   If we're asking about 'self', inherit the handling.  Note
              *   that, for any object type, x.ofKind(x) is always true, so
              *   there's no need for a separate test to see if val equals
              *   self.  
              */
             if (val.ofKind(self))
                 return inherited();
 
             /* use our special value-to-symbol method on the object itself */
             return val.valToSymbol();
             
         case TypeProp:
             /* 
              *   this should usually convert to a symbol, but might have
              *   been allocated dynamically 
              */
             sym = reverseSymtab_[val];
             return (sym != nil ? sym : '(prop)');
 
         case TypeFuncPtr:
         case TypeEnum:
             /* these should always convert directly to symbols */
             sym = reverseSymtab_[val];
             return (sym != nil ? sym : '???');
 
         case TypeNativeCode:
             return '(native code)';
 
         default:
             return '???';
         }
     }
 
     /*
      *   Format a stack frame object (of class T3StackInfo). 
      */
     formatStackFrame(fr, includeSourcePos)
     {
         local ret;
         
         /* see what kind of frame we have */
         if (fr.func_ != nil)
         {
             /* it's a function */
             ret = valToSymbol(fr.func_);
         }
         else if (fr.obj_ != nil)
         {
             /* 
              *   It's an object.property.  Check for one special case we
              *   want to show specially: if the object is an AnonFuncPtr
              *   object, ignore the property and just show it as an
              *   anonymous function. 
              */
             if (fr.obj_.ofKind(AnonFuncPtr))
                 ret = '{anonFunc}';
             else
                 ret = valToSymbol(fr.self_) + '.' + valToSymbol(fr.prop_);
         }
         else
         {
             /* no function or object - must be a system routine */
             ret = '(System)';
         }
 
         /* if it's not a system routine, add the argument list */
         if (!fr.isSystem())
         {
             /* add the open paren */
             ret += '(';
 
             /* add the arguments */
             for (local i = 1, local len = fr.argList_.length() ;
                  i <= len ; ++i)
             {
                 /* if it's not the first one, add a comma */
                 if (i != 1)
                     ret += ', ';
 
                 /* add this value */
                 ret += valToSymbol(fr.argList_[i]);
             }
 
             /* add the close paren */
             ret += ')';
 
             /* if desired, add the source location */
             if (includeSourcePos && fr.srcInfo_ != nil)
                 ret += ' ' + fr.srcInfo_[1] + ', line ' + fr.srcInfo_[2];
         }
 
         /* return the result */
         return ret;
     }
 
     /* the global symbol table */
     symtab_ = nil
 
     /* the global reverse-lookup symbol table */
     reverseSymtab_ = nil
 ;
 
 /* ------------------------------------------------------------------------ */
 /*
  *   Modify the basic Object class to provide a to-symbol mapping
  */
 modify Object
     valToSymbol()
     {
         local sym;
         local found;
         
         /* get my symbol from the global reflection table */
         sym = reflectionServices.reverseSymtab_[self];
 
         /* if we got a symbol, return it */
         if (sym != nil)
             return sym;
 
         /* 
          *   We didn't get a symbol, so there's no source file name.  See
          *   if we can find source-file names for the superclasses, though.
          */
         sym = '(obj:';
         found = nil;
         foreach (local sc in getSuperclassList())
         {
             local scSym;
 
             /* add a comma to the list if this isn't the first element */
             if (sym != '(obj:')
                 sym += ',';
                 
             /* if we have a name here, add it to the list */
             if ((scSym = reflectionServices.reverseSymtab_[sc]) != nil)
             {
                 /* note that we found a named superclass */
                 found = true;
 
                 /* add the superclass name to the list */
                 sym += scSym;
             }
             else
             {
                 /* we don't have a name for this superclass; say so */
                 sym += '(anonymous)';
             }
         }
 
         /* 
          *   if we found any named superclasses, return the list of names;
          *   otherwise, just say (obj) 
          */
         return (found ? sym + ')' : '(obj)');
     }
 ;
 
 /* ------------------------------------------------------------------------ */
 /*
  *   Modify the String intrinsic class to provide a to-symbol mapping 
  */
 modify String
     valToSymbol()
     {
         local ret;
         local i;
         local start;
         
         /* start with an open quote */
         ret = '\'';
 
         /* loop through the string to find each special character */
         for (i = 1, local len = length(), start = 1 ;
              i <= len ; ++i)
         {
             local qu;
 
             /* presume we won't add a quoted character on this round */
             qu = nil;
             
             /* see what we have here */
             switch(substr(i, 1))
             {
             case '\\':
                 qu = '\\\\';
                 break;
                 
             case '\'':
                 qu = '\\\'';
                 break;
 
             case '\n':
                 qu = '\\n';
                 break;
 
             case '\t':
                 qu = '\\t';
                 break;
 
             case '\b':
                 qu = '\\b';
                 break;
 
             case '\ ':
                 qu = '\\ ';
                 break;
 
             case '\^':
                 qu = '\\^';
                 break;
 
             case '\v':
                 qu = '\\v';
                 break;
             }
 
             /* 
              *   if we have a quoted character, add the part up to the
              *   quoted character plus the quoted character 
              */
             if (qu != nil)
             {
                 /* add the part up to here but not including this char */
                 if (i != start)
                     ret += substr(start, i - start);
 
                 /* add the quoted form of the character */
                 ret += qu;
 
                 /* start again after this character */
                 start = i + 1;
             }
         }
 
         /* add the trailing unquoted part if we haven't already */
         if (i != start)
             ret += substr(start, i - start);
 
         /* add a close quote and return the result */
         return ret + '\'';
     }
 ;
 
 /* ------------------------------------------------------------------------ */
 /*
  *   Modify the List intrinsic class to provide a to-symbol mapping 
  */
 modify List
     valToSymbol()
     {
         local ret;
         
         /* start off with an open bracket */
         ret = '[';
 
         /* convert each element to symbolic form */
         for (local i = 1, local len = length() ; i <= len ; ++i)
         {
             /* add a comma if this isn't the first element */
             if (i != 1)
                 ret += ', ';
 
             /* add this element converted to symbolic form */
             ret += reflectionServices.valToSymbol(self[i]);
         }
 
         /* add the close bracket and return the result */
         return ret + ']';
     }
 ;
 
 
 /* ------------------------------------------------------------------------ */
 /*
  *   If desired, modify the BigNumber intrinsic class to provide a
  *   to-symbol mapping.  We only include this modification if the program
  *   is compiled with REFLECT_BIGNUM defined.  
  */
 #ifdef REFLECT_BIGNUM
 #include "bignum.h"
 
 modify BigNumber
     valToSymbol()
     {
         /* use the default formatting */
         return formatString(12);
     }
 ;
 
 #endif /* REFLECT_BIGNUM */
TADS 3 Library Manual
Generated on 9/8/2006 from TADS version 3.0.11