posted on Monday, August 09, 2004 1:43 PM
by
anoras
Declarative JavaScript programming - Source Code
// Enumerations
Modifier={
private:0x2,
public:0x1,
static:0x8,
toString:function(m) {
for (var f in Modifier) {
if (typeof(Modifier[f])=="number") if (Modifier[f]==m) return f.toString();
}
},
isPublic:function(m) {
return (m&Modifier.public)==Modifier.public;
},
isPrivate:function(m) {
return (m&Modifier.private)==Modifier.private;
},
isStatic:function(m) {
return (m&Modifier.static)==Modifier.static;
}
}
WellKnownSignature={
customFunction:1,
string:2,
number:3,
boolean:4,
object:5,
array:6,
date:7,
enumerator:8,
_arrayConstructorSignature:new Array().constructor,
_dateConstructorSignature:new Date().constructor,
_enumeratorConstructorSignature:new Enumerator(new Array()).constructor,
toString:function(s) {
for (var f in WellKnownSignature) {
if (typeof(WellKnownSignature[f])=="number") if (WellKnownSignature[f]==s) return f.toString();
}
}
}
// Reflection class
Reflection={
// Shared
getModifier:function(memberName) {
return (memberName.substr(0,1)=='_'||memberName.substr(0,2)=="m_"||memberName.toLowerCase().indexOf("private")>-1)?Modifier.private:Modifier.public;
},
// Constructor and class reflection
getConstructor:function(obj) {
return obj.constructor;
},
identifyObjectSignature:function(obj) {
switch (typeof(obj)) {
case "function" : return WellKnownSignature.customFunction;
case "string" : return WellKnownSignature.string;
case "boolean" : return WellKnownSignature.boolean;
case "number" : return WellKnownSignature.number;
case "object" :
switch (obj.constructor) {
case WellKnownSignature._arrayConstructorSignature : return WellKnownSignature.array;
case WellKnownSignature._dateConstructorSignature : return WellKnownSignature.date;
case WellKnownSignature._enumeratorConstructorSignature : return WellKnownSignature.enumerator;
default : return WellKnownSignature.object;
}
default :
void (0); // Throw exception
}
},
getClassName:function(obj) {
return Reflection.getMethodName(Reflection.getConstructor(obj));
},
// Method reflection
getMethodName:function(fn) {
try {
var fnName=fn.toString();
fnName=fnName.substring(fnName.indexOf("function")+8,fnName.indexOf('(')).replace(/ /g,'');
return fnName;
} catch (e) {
return "unknownType";
}
},
getMethods:function(obj,protection) {
if (protection==null) protection=Modifier.public|Modifier.private;
var fns=[];
switch (protection) {
case Modifier.public|Modifier.private:
for (var elm in obj) {
if (typeof(obj[elm])=="function") fns[fns.length]=obj[elm];
}
break;
case Modifier.private:
for (var elm in obj) {
if (Reflection.getModifier(elm)==Modifier.private) if (typeof(obj[elm])=="function") fns[fns.length]=obj[elm];
}
break;
case Modifier.public:
for (var elm in obj) {
if (Reflection.getModifier(elm)==Modifier.public) if (typeof(obj[elm])=="function") fns[fns.length]=obj[elm];
}
break;
default:
alert("Unknown protection level: "+protection);
break;
}
return fns;
},
getMethod:function(obj,name) {
for (var elm in obj) {
if (elm==name&&typeof(obj[elm])=="function") return obj[elm];
}
return null;
},
getParameterNames:function(fn) {
var fnStripped=fn.toString().replace(/\t*| */g,'');
fnStripped=fnStripped.substr(fnStripped.indexOf("function(")+9);
fnStripped=fnStripped.substring(0,fnStripped.indexOf(')'));
return fnStripped.split(',');
},
// Field reflection
getFields:function(obj,protection) {
if (protection==null) protection=Modifier.public|Modifier.private;
var flds=[];
switch (protection) {
case Modifier.public|Modifier.private:
for (var elm in obj) if (typeof(obj[elm])!="function") flds[flds.length]=obj[elm];
break;
case Modifier.private:
for (var elm in obj) if (Reflection.getModifier(elm)==Modifier.private) if (typeof(obj[elm])!="function") flds[flds.length]=obj[elm];
break;
case Modifier.public:
for (var elm in obj) if (Reflection.getModifier(elm)==Modifier.public) if (typeof(obj[elm])!="function") flds[flds.length]=obj[elm];
break;
default:
alert("Unknown protection level: "+protection);
break;
}
return flds;
},
// Private methods
_removeWhiteSpace:function(str) {
return str.replace(/\t|^ +/g,'');
},
_getCodeLines:function(fn) {
return fn.split('\n');
}
}
Figure 8 - Reflection.js source
// Reflection extensions
Reflection.getAnnotations=function(fn) {
if (fn) {
var codeLines=Reflection._getCodeLines(Reflection._removeWhiteSpace(fn.toString()));
var annotations=[];
for (var i=0;i<codeLines.length;i++) {
if (codeLines[i].indexOf("///")==0) {
try {
annotations[annotations.length]=Reflection._getAnnotation(codeLines[i]);
} catch (e) {
if (e.number&0xFFFF==5007) {
// throw missing attribute exception
alert(e.message);
}
}
}
}
return annotations;
} else {
// Throw object expected.
}
}
Reflection.getNamedAnnotation=function(fn,name) {
if (fn) {
var codeLines=Reflection._getCodeLines(Reflection._removeWhiteSpace(fn.toString()));
var annotations=[];
for (var i=0;i<codeLines.length;i++) {
if (codeLines[i].indexOf("///")==0) {
try {
if (Reflection._parseAnnotationName(codeLines[i]))return Reflection._getAnnotation(codeLines[i]);
} catch (e) {
if (e.number&0xFFFF==5007) {
// throw missing attribute exception
alert(e.message);
}
}
}
}
}
return null;
}
Reflection._getAnnotation=function(str) {
var annotation=eval("new "+Reflection._parseAnnotationName(str)+"()");
annotation=Reflection._setNameValuePairs(annotation,str);
return annotation;
}
Reflection._setNameValuePairs=function(annotationInstance,annotationInfo) {
var annotationName=Reflection._parseAnnotationName(annotationInfo);
var pairs=annotationInfo.substr(annotationInfo.indexOf(annotationName)+annotationName.length+1);
pairs=pairs.substr(0,pairs.indexOf(')')).split(',');
if (pairs.length==1&&pairs[0].indexOf('=')==-1) {
annotationInstance=eval("new "+annotationName+'('+pairs[0]+");");
return annotationInstance;
} else {
for (var i=0; i<pairs.length; i++) {
var nameValue=pairs[i].split('=');
try {
annotationInstance._setMember(nameValue[0],nameValue[1]);
} catch (e) {
alert(e.message + " (" + e.number+")<BR>");
}
}
}
return annotationInstance;
}
Reflection._parseAnnotationName=function(str) {
return str.substring(str.indexOf('@')+1,str.indexOf('(')).replace(/ /g,'');
}
Annotation=function() {
}
Annotation.prototype._setMember=function(name,value) {
eval("this."+name+'='+value);
}
Figure 9 - Annotation.js source