reflect.t | documentation |
#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 */
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3
Generated on 5/16/2013 from TADS version 3.1.3