28 #include "function_object.h" 31 #include "operations.h" 50 char hexdigits[] =
"0123456789ABCDEF";
55 for (
int k = 0; k <
string.size(); k++) {
58 if (unescapedSet.
find(C) >= 0) {
59 if (encbufLen+1 >= encbufAlloc)
60 encbuf = (
UChar*)realloc(encbuf,(encbufAlloc *= 2)*
sizeof(
UChar));
61 encbuf[encbufLen++] = C;
64 unsigned char octets[4];
67 unsigned short zzzzzzz = C.uc;
71 else if (C.uc <= 0x07FF) {
72 unsigned short zzzzzz = C.uc & 0x3F;
73 unsigned short yyyyy = (C.uc >> 6) & 0x1F;
74 octets[0] = 0xC0 | yyyyy;
75 octets[1] = 0x80 | zzzzzz;
78 else if (C.uc >= 0xD800 && C.uc <= 0xDBFF) {
81 if (k + 1 >=
string.size()) {
83 exec->setException(err);
88 unsigned short Cnext =
UChar(
string[++k]).uc;
90 if (Cnext < 0xDC00 || Cnext > 0xDFFF) {
92 exec->setException(err);
97 unsigned short zzzzzz = Cnext & 0x3F;
98 unsigned short yyyy = (Cnext >> 6) & 0x0F;
99 unsigned short xx = C.uc & 0x03;
100 unsigned short wwww = (C.uc >> 2) & 0x0F;
101 unsigned short vvvv = (C.uc >> 6) & 0x0F;
102 unsigned short uuuuu = vvvv+1;
103 octets[0] = 0xF0 | (uuuuu >> 2);
104 octets[1] = 0x80 | ((uuuuu & 0x03) << 4) | wwww;
105 octets[2] = 0x80 | (xx << 4) | yyyy;
106 octets[3] = 0x80 | zzzzzz;
109 else if (C.uc >= 0xDC00 && C.uc <= 0xDFFF) {
111 exec->setException(err);
117 unsigned short zzzzzz = C.uc & 0x3F;
118 unsigned short yyyyyy = (C.uc >> 6) & 0x3F;
119 unsigned short xxxx = (C.uc >> 12) & 0x0F;
120 octets[0] = 0xE0 | xxxx;
121 octets[1] = 0x80 | yyyyyy;
122 octets[2] = 0x80 | zzzzzz;
126 while (encbufLen+3*octets_len >= encbufAlloc)
127 encbuf = (
UChar*)realloc(encbuf,(encbufAlloc *= 2)*
sizeof(
UChar));
129 for (
int j = 0; j < octets_len; j++) {
130 encbuf[encbufLen++] =
'%';
131 encbuf[encbufLen++] = hexdigits[octets[j] >> 4];
132 encbuf[encbufLen++] = hexdigits[octets[j] & 0x0F];
137 UString encoded(encbuf,encbufLen);
142 static bool decodeHex(
UChar hi,
UChar lo,
unsigned short *val)
145 if (hi.uc >=
'0' && hi.uc <=
'9')
146 *val = (hi.uc-
'0') << 4;
147 else if (hi.uc >=
'a' && hi.uc <=
'f')
148 *val = 10+(hi.uc-
'a') << 4;
149 else if (hi.uc >=
'A' && hi.uc <=
'F')
150 *val = 10+(hi.uc-
'A') << 4;
154 if (lo.uc >=
'0' && lo.uc <=
'9')
156 else if (lo.uc >=
'a' && lo.uc <=
'f')
157 *val |= 10+(lo.uc-
'a');
158 else if (lo.uc >=
'A' && lo.uc <=
'F')
159 *val |= 10+(lo.uc-
'A');
172 for (
int k = 0; k <
string.size(); k++) {
175 if (C !=
UChar(
'%')) {
177 if (decbufLen+1 >= decbufAlloc)
178 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
179 decbuf[decbufLen++] = C;
185 if (k+2 >=
string.size()) {
187 exec->setException(err);
193 if (!decodeHex(
string[k+1],
string[k+2],&B)) {
195 exec->setException(err);
202 if (decbufLen+2 >= decbufAlloc)
203 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
205 if ((B & 0x80) == 0) {
212 while (((B << n) & 0x80) != 0)
215 if (n < 2 || n > 4) {
217 exec->setException(err);
222 if (k+3*(n-1) >=
string.size()) {
224 exec->setException(err);
229 unsigned short octets[4];
231 for (
int j = 1; j < n; j++) {
234 !decodeHex(
string[k+1],
string[k+2],&B) ||
235 ((B & 0xC0) != 0x80)) {
237 exec->setException(err);
247 const unsigned long replacementChar = 0xFFFD;
250 unsigned long yyyyy = octets[0] & 0x1F;
251 unsigned long zzzzzz = octets[1] & 0x3F;
252 V = (yyyyy << 6) | zzzzzz;
256 C =
UChar((
unsigned short)V);
259 unsigned long xxxx = octets[0] & 0x0F;
260 unsigned long yyyyyy = octets[1] & 0x3F;
261 unsigned long zzzzzz = octets[2] & 0x3F;
262 V = (xxxx << 12) | (yyyyyy << 6) | zzzzzz;
265 if (V < 0x800 || V == 0xFFFE || V == 0xFFFF ||
266 (V >= 0xD800 && V <= 0xDFFF))
268 C =
UChar((
unsigned short)V);
272 unsigned long uuuuu = ((octets[0] & 0x07) << 2) | ((octets[1] >> 4) & 0x03);
273 unsigned long vvvv = uuuuu-1;
276 exec->setException(err);
280 unsigned long wwww = octets[1] & 0x0F;
281 unsigned long xx = (octets[2] >> 4) & 0x03;
282 unsigned long yyyy = octets[2] & 0x0F;
283 unsigned long zzzzzz = octets[3] & 0x3F;
284 unsigned short H = 0xD800 | (vvvv << 6) | (wwww << 2) | xx;
285 unsigned short L = 0xDC00 | (yyyy << 6) | zzzzzz;
286 decbuf[decbufLen++] =
UChar(H);
287 decbuf[decbufLen++] =
UChar(L);
292 if (reservedSet.
find(C) < 0) {
293 decbuf[decbufLen++] = C;
297 while (decbufLen+k-start+1 >= decbufAlloc)
298 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
299 for (
int p = start; p <= k; p++)
300 decbuf[decbufLen++] =
string[p];
304 UString decoded(decbuf,decbufLen);
309 static UString uriReserved =
";/?:@&=+$,";
310 static UString uriAlpha =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
311 static UString DecimalDigit =
"0123456789";
312 static UString uriMark =
"-_.!~*'()";
313 static UString uriUnescaped = uriAlpha+DecimalDigit+uriMark;
317 const ClassInfo FunctionImp::info = {
"Function", &InternalFunctionImp::info, 0, 0};
323 ~Parameter() {
delete next; }
331 static_cast<
FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
332 ), param(0L), line0(-1), line1(-1), sid(-1)
338 FunctionImp::~FunctionImp()
343 bool FunctionImp::implementsCall()
const 354 exec->
context().imp(),
this, &args);
356 newExec.setException(exec->exception());
359 processParameters(&newExec, args);
361 processVarDecls(&newExec);
363 ctx.setLines(line0,line0);
364 Debugger *dbg = exec->interpreter()->imp()->debugger();
366 if (!dbg->enterContext(&newExec)) {
375 ctx.setLines(line1,line1);
380 if (!dbg->exitContext(&newExec,comp)) {
388 if (newExec.hadException())
389 exec->setException(newExec.exception());
392 CString n = ident.isEmpty() ?
CString(
"(internal)") : ident.ustring().cstring();
393 if (comp.complType() == Throw) {
395 printInfo(exec, n.c_str(), comp.value());
396 }
else if (comp.complType() == ReturnValue) {
398 printInfo(exec, n.c_str(), comp.value());
400 fprintf(stderr,
"%s returns: undefined\n", n.c_str());
403 if (comp.complType() == Throw) {
404 exec->setException(comp.value());
407 else if (comp.complType() == ReturnValue)
413 void FunctionImp::addParameter(
const Identifier &n)
415 Parameter **p = ¶m;
419 *p =
new Parameter(n);
422 Identifier FunctionImp::parameterProperty(
int index)
const 427 for (p = param; p && pos < index; p = p->next)
435 for (p = p->next; p; p = p->next)
442 UString FunctionImp::parameterString()
const 445 const Parameter *p = param;
449 s += p->name.ustring();
458 void FunctionImp::processParameters(
ExecState *exec,
const List &args)
463 fprintf(stderr,
"---------------------------------------------------\n" 464 "processing parameters for %s call\n",
465 name().isEmpty() ?
"(internal)" : name().ascii());
470 Parameter *p = param;
472 if (it != args.
end()) {
474 fprintf(stderr,
"setting parameter %s ", p->name.ascii());
475 printInfo(exec,
"to", *it);
477 variable.
put(exec, p->name, *it);
486 for (
int i = 0; i < args.
size(); i++)
487 printInfo(exec,
"setting argument", args[i]);
492 void FunctionImp::processVarDecls(
ExecState * )
499 if (propertyName == argumentsPropertyName) {
505 if (context->function() ==
this)
506 return static_cast<ActivationImp *>
507 (context->activationObject())->
get(exec, propertyName);
508 context = context->callingContext();
514 if (propertyName == lengthPropertyName) {
515 const Parameter * p = param;
524 if (propertyName == callerPropertyName) {
527 if (context->function() ==
this) {
529 if (cc && cc->function())
530 return Value(cc->function());
534 context = context->callingContext();
539 return InternalFunctionImp::get(exec, propertyName);
544 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
546 InternalFunctionImp::put(exec, propertyName, value, attr);
551 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
553 return InternalFunctionImp::hasProperty(exec, propertyName);
558 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
560 return InternalFunctionImp::deleteProperty(exec, propertyName);
566 const ClassInfo DeclaredFunctionImp::info = {
"Function", &FunctionImp::info, 0, 0};
575 line0 = body->firstLine();
576 line1 = body->lastLine();
577 sid = body->sourceId();
580 DeclaredFunctionImp::~DeclaredFunctionImp()
586 bool DeclaredFunctionImp::implementsConstruct()
const 595 Value p =
get(exec,prototypePropertyName);
596 if (p.
type() == ObjectType)
597 proto =
Object(static_cast<ObjectImp*>(p.imp()));
601 Object obj(
new ObjectImp(proto));
603 Value res = call(exec,obj,args);
605 if (res.
type() == ObjectType)
615 if (result.complType() == Throw || result.complType() == ReturnValue)
620 void DeclaredFunctionImp::processVarDecls(
ExecState *exec)
622 body->processVarDecls(exec);
631 class ShadowImp :
public ObjectImp {
633 ShadowImp(ObjectImp *_obj,
Identifier _prop) : obj(_obj), prop(_prop) {}
636 virtual const ClassInfo *classInfo()
const {
return &info; }
643 const ClassInfo ShadowImp::info = {
"Shadow", 0, 0, 0};
645 void ShadowImp::mark()
656 const ClassInfo ArgumentsImp::info = {
"Arguments", 0, 0, 0};
661 : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()), activation(act)
664 putDirect(calleePropertyName, func, DontEnum);
665 putDirect(lengthPropertyName, args.
size(), DontEnum);
668 for (
int i = 0; arg != args.
end(); arg++, i++) {
671 Object shadow(
new ShadowImp(act,prop));
672 ObjectImp::put(exec,Identifier::from(i), shadow, DontEnum);
675 ObjectImp::put(exec,Identifier::from(i), *arg, DontEnum);
681 void ArgumentsImp::mark()
684 if (!activation->marked())
690 Value val = ObjectImp::get(exec,propertyName);
691 assert(SimpleNumber::is(val.imp()) || !val.imp()->isDestroyed());
693 if (obj.isValid() && obj.inherits(&ShadowImp::info)) {
694 ShadowImp *shadow =
static_cast<ShadowImp*
>(val.imp());
695 return activation->
get(exec,shadow->prop);
703 const Value &value,
int attr)
705 Value val = ObjectImp::get(exec,propertyName);
707 if (obj.
isValid() && obj.inherits(&ShadowImp::info)) {
708 ShadowImp *shadow =
static_cast<ShadowImp*
>(val.imp());
709 activation->
put(exec,shadow->prop,value,attr);
712 ObjectImp::put(exec,propertyName,value,attr);
718 const ClassInfo ActivationImp::info = {
"Activation", 0, 0, 0};
721 ActivationImp::ActivationImp(
FunctionImp *
function,
const List &arguments)
722 : _function(function), _arguments(true), _argumentsObject(0)
724 _arguments = arguments.
copy();
730 if (propertyName == argumentsPropertyName) {
732 ValueImp *v = getDirect(propertyName);
737 if (!_argumentsObject)
738 _argumentsObject =
new ArgumentsImp(exec, _function, _arguments, const_cast<ActivationImp*>(
this));
739 return Value(_argumentsObject);
741 return ObjectImp::get(exec, propertyName);
746 if (propertyName == argumentsPropertyName)
748 return ObjectImp::hasProperty(exec, propertyName);
753 if (propertyName == argumentsPropertyName)
755 return ObjectImp::deleteProperty(exec, propertyName);
758 void ActivationImp::mark()
761 if (_function && !_function->marked())
764 if (_argumentsObject && !_argumentsObject->marked())
765 _argumentsObject->mark();
776 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
780 CodeType GlobalFuncImp::codeType()
const 782 return id == Eval ? EvalCode : codeType();
785 bool GlobalFuncImp::implementsCall()
const 794 static const char do_not_escape[] =
795 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 796 "abcdefghijklmnopqrstuvwxyz" 803 if (x.
type() != StringType)
811 fprintf(stderr,
"eval(): %s\n", s.
ascii());
814 FunctionBodyNode *progNode = Parser::parse(s.
data(),s.
size(),&source,&errLine,&errMsg);
817 Debugger *dbg = exec->interpreter()->imp()->debugger();
819 bool cont = dbg->sourceParsed(exec,source->sid,s,errLine);
829 exec->interpreter()->imp()->addSourceCode(source);
835 exec->setException(err);
852 newExec.setException(exec->exception());
854 ctx.setLines(progNode->firstLine(),progNode->firstLine());
856 if (!dbg->enterContext(&newExec)) {
860 if (progNode->deref())
867 progNode->processVarDecls(&newExec);
872 ctx.setLines(progNode->lastLine(),progNode->lastLine());
873 if (dbg && !dbg->exitContext(&newExec,c))
876 else if (newExec.hadException())
877 exec->setException(newExec.exception());
878 else if (c.complType() == Throw)
879 exec->setException(c.value());
880 else if (c.isValueCompletion())
883 if (progNode->deref())
891 CString cstr = args[0].toString(exec).cstring();
892 const char* startptr = cstr.c_str();
893 while ( *startptr && isspace( *startptr ) )
898 base = args[1].toInt32(exec);
901 if (*startptr ==
'-') {
905 else if (*startptr ==
'+') {
910 bool leading0 =
false;
911 if ((base == 0 || base == 16) &&
912 (*startptr ==
'0' && (startptr[1] ==
'x' || startptr[1] ==
'X'))) {
916 else if (base == 0 && *startptr ==
'0') {
921 else if (base == 0) {
925 if (base < 2 || base > 36) {
931 for (; *startptr; startptr++) {
933 if (*startptr >=
'0' && *startptr <=
'9')
934 thisval = *startptr -
'0';
935 else if (*startptr >=
'a' && *startptr <=
'z')
936 thisval = 10 + *startptr -
'a';
937 else if (*startptr >=
'A' && *startptr <=
'Z')
938 thisval = 10 + *startptr -
'A';
940 if (thisval < 0 || thisval >= base)
948 if (index == 0 && !leading0)
951 res =
Number(
double(val)*sign);
956 UString str = args[0].toString(exec);
960 const char *c = str.
ascii();
963 isHex = (c[0] ==
'0' && (c[1] ==
'x' || c[1] ==
'X'));
972 res =
Boolean(isNaN(args[0].toNumber(exec)));
975 double n = args[0].toNumber(exec);
976 res =
Boolean(!isNaN(n) && !isInf(n));
980 res =
String(decodeURI(exec,args[0].toString(exec),uriReserved+
"#"));
982 case DecodeURIComponent:
983 res =
String(decodeURI(exec,args[0].toString(exec),
""));
986 res =
String(encodeURI(exec,args[0].toString(exec),uriReserved+uriUnescaped+
"#"));
988 case EncodeURIComponent:
989 res =
String(encodeURI(exec,args[0].toString(exec),uriUnescaped));
992 UString r =
"", s, str = args[0].toString(exec);
993 const UChar *c = str.data();
994 for (
int k = 0; k < str.size(); k++, c++) {
998 sprintf(tmp,
"%%u%04X", u);
1000 }
else if (u != 0 && strchr(do_not_escape, (
char)u)) {
1004 sprintf(tmp,
"%%%02X", u);
1013 UString s =
"", str = args[0].toString(exec);
1014 int k = 0, len = str.
size();
1016 const UChar *c = str.data() + k;
1018 if (*c ==
UChar(
'%') && k <= len - 6 && *(c+1) ==
UChar(
'u')) {
1019 if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
1020 Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
1021 u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
1022 (c+4)->uc, (c+5)->uc);
1026 }
else if (*c ==
UChar(
'%') && k <= len - 3 &&
1027 Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
1028 u =
UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
1040 puts(args[0].toString(exec).ascii());
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents...
Type type() const
Returns the type of value.
bool is8Bit() const
Use this if you want to make sure that this string is a plain ASCII string.
Base class for all function objects.
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Represents an primitive Number value.
Object & globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
int find(const UString &f, int pos=0) const
Represents an primitive Null value.
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
8 bit char based string class
static Object create(ExecState *exec, ErrorType errtype=GeneralError, const char *message=0, int lineno=-1, int sourceId=-1)
Factory method for error objects.
The initial value of Function.prototype (and thus all objects created with the Function constructor) ...
bool isEmpty() const
Returns that the identifiers string is set, but is empty.
double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
Attempts an conversion to a number.
ListIterator begin() const
Represents an primitive Undefined value.
Implementation class for functions implemented in JS.
Represents an primitive String value.
static Object dynamicCast(const Value &v)
Converts a Value into an Object.
ValueImp is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects i...
Context context() const
Returns the execution context associated with this execution state.
TQString name(StdAccel id)
Completion objects are used to convey the return status and value from functions. ...
Object builtinObjectPrototype() const
Returns the builtin "Object.prototype" object.
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Represents an primitive Boolean value.
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
List copy() const
Make a copy of the list.
bool isValid() const
Returns whether or not this is a valid value.
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
static const Identifier & null()
Creates an empty Identifier.
Represents the current state of script execution.
Represents an Identifier for a Javascript object.
const UChar * data() const
Iterator for KJS::List objects.