#charset "us-ascii"
/*
* Copyright (c) 2000, 2006 Michael J. Roberts
*
* This file is part of TADS 3.
*/
#include <tads.h>
#include <strbuf.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();
/* check for intrinsic classes */
if (IntrinsicClass.isIntrinsicClass(val))
{
/* intrinsic classes should always be in the symbol table */
sym = reverseSymtab_[val];
return (sym != nil ? sym : '{intrinsicClass}');
}
/* 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:
/*
* look for a name; if it doesn't have one, it must be an
* anonymous function
*/
sym = reverseSymtab_[val];
return (sym != nil ? sym : '{anonFunc}');
case TypeEnum:
/* these should always convert directly to symbols */
sym = reverseSymtab_[val];
return (sym != nil ? sym : '{enum}');
case TypeBifPtr:
/* these should always convert directly to symbols */
sym = reverseSymtab_[val];
return (sym != nil ? sym : '{intrinsicFunc}');
case TypeNativeCode:
return '{native code}';
default:
return '???';
}
}
/*
* Format a stack frame object (of class T3StackInfo).
*/
formatStackFrame(fr, includeSourcePos)
{
local ret = new StringBuffer();
/* see what kind of frame we have */
if (fr.func_ != nil)
{
/* it's a function */
ret.append(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.append('{anonFunc}');
else
{
ret.append(valToSymbol(fr.self_));
ret.append('.');
ret.append(valToSymbol(fr.prop_));
}
}
else
{
/* no function or object - must be a system routine */
ret.append('(System)');
}
/* if it's not a system routine, add the argument list */
if (fr.argList_ != nil)
{
/* add the open paren */
ret.append('(');
/* add the arguments */
local i, len = fr.argList_.length();
for (i = 1 ; i <= len ; ++i)
{
/* if it's not the first one, add a comma */
if (i != 1)
ret.append(', ');
/* add this value */
ret.append(valToSymbol(fr.argList_[i]).htmlify());
}
/* add any named arguments */
if (fr.namedArgs_ != nil)
{
/* add each key from the named argument table */
fr.namedArgs_.forEachAssoc(function(key, val)
{
/* add a separator if this isn't the first item */
if (i++ != 1)
ret.append(', ');
/* add this "name: value" */
ret.append(key);
ret.append(':');
ret.append(valToSymbol(val));
});
}
/* add the close paren */
ret.append(')');
/* if desired, add the source location */
if (includeSourcePos && fr.srcInfo_ != nil)
{
ret.append(' ');
ret.append(fr.srcInfo_[1]);
ret.append(', line ');
ret.append(fr.srcInfo_[2]);
}
}
/* return the result */
return toString(ret);
}
/* the global symbol table */
symtab_ = nil
/* the global reverse-lookup symbol table */
reverseSymtab_ = nil
;
/* ------------------------------------------------------------------------ */
/*
* Export the reflection services interfaces used by the VM
*/
export reflectionServices 'reflection.reflectionServices';
export valToSymbol 'reflection.valToSymbol';
/* ------------------------------------------------------------------------ */
/*
* Modify the basic Object class to provide a to-symbol mapping
*/
modify Object
valToSymbol()
{
/* get my symbol from the global reflection table */
local 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:';
local 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 */
Adv3Lite Library Reference Manual
Generated on 03/07/2024 from adv3Lite version 2.1